#include "particles.h"

/*------------------------------------------------------------------------------
  Constructor
------------------------------------------------------------------------------*/
Particles::Particles():Entity()
{  
	Entity::setScale(1.f);
  	m_iAliveParticles=0;
  	m_iNumParticles=0;
  	m_fRatio=1;
  	m_pTexture=NULL;  
  	m_eType=PART_FIRE;  
  	m_fXAcel=0;
  
//  m_eProfundidad=Z_DELANTE;
}

/*------------------------------------------------------------------------------
  Destructor
------------------------------------------------------------------------------*/
Particles::~Particles(){
}

/*------------------------------------------------------------------------------
  Initializes particle system
------------------------------------------------------------------------------*/
bool Particles::init(Texture *_texture,int _numParticles,EParticlesType _type,float _life,float _gravity,float _X,float _Y,float _Z,float _colorR,float _colorG,float _colorB){

	if(!Entity::init(_X,_Y,_Z,0.f,1.f,1.f,1.f) || !_texture)
		return false;
	
	int i;	
	
	m_pLog=&Log::getInstance();
	
	Entity::setColor(_colorR,_colorG,_colorB);
	
	m_pTexture=_texture;
	m_fGravity=_gravity;    
  	m_fInitialLife=_life;  	
	m_iNumParticles=_numParticles;  
  	m_eType=_type;
	m_fParticleSize=50.f;
  
  	if(m_iNumParticles>MAX_PARTICLES)
    	m_iNumParticles=MAX_PARTICLES;
  
  	m_iAliveParticles=m_iNumParticles;
    
  	for(i=0;i<m_iNumParticles;i++){
		TParticle *part=new TParticle;
		part->particle_physics.init();
		particleReset(part);
		m_particles.push_back(part);
  	}
  
  	m_pLog->debug("+ Particles initialized");   
	return true;
}

/*------------------------------------------------------------------------------
  Free memory
------------------------------------------------------------------------------*/
void Particles::freeMemory()
{
  m_pTexture=NULL;
  m_pLog->debug("- Particles free");    
}

/*------------------------------------------------------------------------------
  Reset a particle. This function set the particle to a initial state
------------------------------------------------------------------------------*/
void Particles::particleReset(TParticle *_particle)
{
  	float v,phi,theta,acelmod;
  
  	v = 0.8*frand()+0.2;
  	phi = frand()*M_PI;
  	theta = 2.0*frand()*M_PI;
  	acelmod=50;
  	_particle->bActive=true;
  	_particle->fGravityAcel=m_fGravity;
  
  	switch(m_eType){
		/*--------------------------------------------*/
		case PART_EXPLOSION:
		case PART_AURA:
			acelmod=70;
			_particle->fLife=m_fInitialLife;     
			_particle->fFade=frand();
	  
			_particle->fR=Entity::getColorR();
			_particle->fG=Entity::getColorG();
			_particle->fB=Entity::getColorB();

			
			_particle->fX=Entity::getX()+((v * cos(theta) * sin(phi))/(m_iNumParticles/5)*m_fRatio);
			_particle->fY=Entity::getY()+((v * cos(phi))/(m_iNumParticles/5)*m_fRatio);
			_particle->fZ=Entity::getZ()+(v * sin(theta) * sin(phi))/(m_iNumParticles/5);
		
			_particle->fXd=  (v * cos(theta) * sin(phi))/acelmod;
			_particle->fYd= ((v * cos(phi))/acelmod)+(m_fGravity*frand());
			_particle->fZd=  (v * sin(theta) * sin(phi))/acelmod;
			
			
		break;    
    
		/*--------------------------------------------*/
		case PART_FIRE:     
			_particle->fLife=m_fInitialLife;
			_particle->fFade=(frand())+0.03;
	  
			_particle->fR=Entity::getColorR();
			_particle->fG=Entity::getColorG();
			_particle->fB=Entity::getColorB();

			_particle->particle_physics.setPosition(Vector2(getX()+((v * cos(theta) * sin(phi))/(m_iNumParticles/5)*m_fRatio),
															getY()+((v * cos(phi))/(m_iNumParticles/5)*m_fRatio)));
			
			_particle->particle_physics.setAngle(-90);
			_particle->particle_physics.setSpeed(frand());


			_particle->fX=Entity::getX()+(((v * cos(theta) * sin(phi))/(acelmod))*m_fRatio);
			_particle->fY=Entity::getY()+(((v * cos(phi))/acelmod)*m_fRatio);
			_particle->fZ=Entity::getZ()+(v * sin(theta) * sin(phi))/acelmod;    
			
			_particle->fXd= 0;
			_particle->fYd= (m_fGravity*frand());
			_particle->fZd= 0;
		break;    
  	}
}

/*------------------------------------------------------------------------------
  Draws all particles
------------------------------------------------------------------------------*/
void Particles::draw()
{
	list<TParticle *>::iterator it;
	glEnable( GL_BLEND );
    glBlendFunc( GL_DST_ALPHA, GL_ONE );
	
	glPushMatrix();
	glLoadIdentity();
	
	//~ const Vector2 *pos=getPosition();
	//~ glTranslatef(pos->x,pos->y,getZ());
	
    glPointParameterfARB( GL_POINT_FADE_THRESHOLD_SIZE_ARB, 10.0f );
    glPointParameterfARB( GL_POINT_SIZE_MIN_ARB, 1.0f );
    glPointParameterfARB( GL_POINT_SIZE_MAX_ARB, 2.0f );
	
	glTexEnvf( GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE );	
    glEnable( GL_POINT_SPRITE_ARB );

    glPointSize( m_fParticleSize );
	m_pTexture->bind(); 
		
	glBegin( GL_POINTS );
	for(it=m_particles.begin();it!=m_particles.end();it++)
	{
		if((*it)->bActive){
			glColor4f( (*it)->fR,(*it)->fG,(*it)->fB,(*it)->fLife);
			glVertex2f( (*it)->particle_physics.getX(),(*it)->particle_physics.getY());
			//~ glVertex2f( (*it)->fX,(*it)->fY);
		}
	}
	glEnd();
	
	glDepthMask( GL_TRUE );
    //~ glDisable( GL_BLEND );
	glDisable( GL_POINT_SPRITE_ARB );	
	glPopMatrix();
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void Particles::update()
{
	list<TParticle *>::iterator it;
	
	Physics::update();
	
	for(it=m_particles.begin();it!=m_particles.end();it++)
		particleUpdate((*it));
}

/*------------------------------------------------------------------------------
------------------------------------------------------------------------------*/
void Particles::particleUpdate(TParticle *_particle)
{
	_particle->fX+=_particle->fXd+m_fXAcel;
  	_particle->fY+=_particle->fYd;//+_particle->fGravityAcel;
  	_particle->fZ+=_particle->fZd;
    
  	_particle->fGravityAcel+=m_fGravity;
  
  	_particle->fLife-=_particle->fFade;
  
  	_particle->particle_physics.update();
	
	
  	if(_particle->fLife<=0){   
    	switch(m_eType)
    	{
      		case PART_EXPLOSION:
				if(!_particle->bActive)return;
				
        		m_iAliveParticles--;
        		_particle->bActive=false;
				
        		if(m_iAliveParticles<=0){
          			Entity::setAlive(false);
        		}
      		break;
      		case PART_AURA:
        		particleReset(_particle);
      		break;
      		case PART_FIRE:
        		particleReset(_particle);
      		break;
    	}
  	}
}

/*------------------------------------------------------------------------------
  Is particle alive?  
------------------------------------------------------------------------------*/
bool Particles::getAlive()
{
  	if(m_iAliveParticles>0 && Entity::isAlive())  
    	return true;  
  
  	return false;
}

